package cn.jofei.common.monitor.cmds;

import cn.jofei.common.utils.Streams;
import cn.jofei.common.utils.Utils;
import cn.jofei.common.util.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.Random;
import java.util.concurrent.TimeUnit;

/**
 * 脚本执行器
 *
 * @author Jofei Bao
 * @version project-manager v1.0.1
 * @date 2022年06月03日 16:14
 */
public class ShellActuator {

    private final static Logger logger = LoggerFactory.getLogger(ShellActuator.class);

    private static final String EXEC_PATH = "/root/temp";

    private static final String EXEC_NAME = "simple";

    /**
     * 执行简单命令
     *
     * @param cmd 命令
     * @return 结果
     */
    public static String executeSimple(String cmd) {
        return executeSimple(cmd, null);
    }

    /**
     * 执行简单命令
     *
     * @param cmd 命令
     * @param dir 执行路径
     * @return 结果
     */
    public static String executeSimple(String cmd, File dir) {
        Process exec = null;
        String parentPath = EXEC_PATH;
        if (dir != null) {
            parentPath = dir.getAbsolutePath();
        }
        String shellName = EXEC_NAME + (Utils.isWin() ? ".cmd" : ".sh");
        //写执行脚本
        File cmdFile = new File(parentPath + "/" + shellName);
        try {
            File logFile = File.createTempFile(generateName() ,"log");
            //写脚本文件 ，之后用cmd命令调用
            dir = Utils.createFile(cmdFile);
            FileWriter fileWriter = new FileWriter(cmdFile);
            fileWriter.write((Utils.isWin() ? "@echo off\n" : "") + new String(cmd.getBytes(), StandardCharsets.UTF_8));
            fileWriter.flush();
            fileWriter.close();

            if (Utils.isWin()) {
                //文件转化为ANSI格式
                convertToGBK(cmdFile);
                exec = new ProcessBuilder("cmd", "/c", shellName)
                        .directory(dir)
                        .redirectOutput(logFile)
                        .redirectErrorStream(false)
                        .start();
            } else {
                cmdFile.setExecutable(true);
                exec = new ProcessBuilder("sh", "-c", "./" + shellName)
                        .directory(dir)
                        .redirectOutput(logFile)
                        .redirectErrorStream(false)
                        .start();
            }
            //等待脚本执行完成
            exec.waitFor(1, TimeUnit.MINUTES);
            String result = Resource.readToString(logFile);
            return Utils.isWin() ? result.replaceAll("\u0000", "") : result;
        } catch (Exception e) {
            logger.error("执行脚本：【{}】出错！", cmd, e);
            return null;
        } finally {
            if (exec != null) {
                exec.destroy();
                exec.destroyForcibly();
            }
            cmdFile.delete();
        }
    }

    /**
     * 将文件转换为GBK编码
     *
     * @param file 需要转换的文件
     */
    private static void convertToGBK(File file) {
        BufferedReader buf = null;
        OutputStreamWriter pw = null;
        String allstr = "";
        //用于输入换行符的字节码
        byte[] c = new byte[2];
        c[0] = 0x0d;
        c[1] = 0x0a;
        String t = new String(c);
        try {
            buf = new BufferedReader(new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8));
            String str;
            while ((str = buf.readLine()) != null) {
                allstr = allstr + str.replaceAll(t, "") + t;
            }
            pw = new OutputStreamWriter(new FileOutputStream(file), "GBK");
            pw.write(allstr);
        } catch (Exception e) {
            logger.error("将文件转换为GBK失败", e);
        } finally {
            Streams.safeClose(buf);
            Streams.safeClose(pw);
        }
    }

    private static String generateName() {
        return System.currentTimeMillis() + new Random().nextInt(1000) + "";
    }
}
